package com.bianguo.android.bprinter.view.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.bianguo.android.bprinter.R;

import java.util.ArrayList;

public class DBoardView extends View {

    //最大撤回数
    public static final int MAX_RECALL_COUNT = 15;
    public static final int CUT_RESERVE_SIZE = 10;
    //画笔
    private Paint mPaint;
    //橡皮
    private Paint erasePaint;
    private float mPreX, mPreY;
    private ArrayList<DrawInfo> drawInfoList, recallInfoList;
    private int lineWidth, lineColor;
    private Mode mMode;
    private Bitmap mBufferBitmap;
    private Canvas mBufferCanvas;

    public enum Mode {
        DRAW,
        ERASE
    }

    public DBoardView(Context context) {
        this(context, null);
    }

    public DBoardView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DBoardView);
        lineWidth = typedArray.getInteger(R.styleable.DBoardView_line_width, 8);
        lineColor = typedArray.getColor(R.styleable.DBoardView_line_color, Color.BLACK);
        typedArray.recycle();
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(lineWidth);
        mPaint.setColor(lineColor);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setXfermode(null);

        erasePaint = new Paint();
        erasePaint.setStyle(Paint.Style.STROKE);
        erasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        erasePaint.setAlpha(0);
        erasePaint.setAntiAlias(true);
        erasePaint.setStrokeWidth(lineWidth);
        erasePaint.setStrokeCap(Paint.Cap.ROUND);
        erasePaint.setStrokeJoin(Paint.Join.ROUND);

        drawInfoList = new ArrayList<>();
        recallInfoList = new ArrayList<>();
        mMode = Mode.DRAW;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mBufferBitmap == null) {
            int measureWidth = getMeasuredWidth();
            int measureHeight = getMeasuredHeight();
            mBufferBitmap = Bitmap.createBitmap(measureWidth, measureHeight, Bitmap.Config.ARGB_8888);
            mBufferCanvas = new Canvas(mBufferBitmap);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (DrawInfo drawInfo : drawInfoList) {
            Paint paint = drawInfo.getPaint();
            mBufferCanvas.drawPath(drawInfo.getPath(), paint);
        }
        if (mBufferBitmap != null) {
            canvas.drawBitmap(mBufferBitmap, 0, 0, null);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPreX = event.getX();
                mPreY = event.getY();
                DrawInfo drawInfo = new DrawInfo();
                drawInfo.setPath(getPath(mPreX, mPreY));
                drawInfo.setMode(mMode);
                ArrayList<PointF> points = new ArrayList<>();
                points.add(new PointF(mPreX, mPreY));
                drawInfo.setPoints(points);
                switch (mMode) {
                    case DRAW:
                        drawInfo.setPaint(mPaint);
                        break;
                    case ERASE:
                        drawInfo.setPaint(erasePaint);
                        break;
                }
                drawInfoList.add(drawInfo);
                break;
            case MotionEvent.ACTION_MOVE:
                DrawInfo drawFo = drawInfoList.get(drawInfoList.size() - 1);
                Path mPath = drawFo.getPath();
                ArrayList<PointF> drawPoints = drawFo.getPoints();
                float x = (event.getX() + mPreX) / 2;
                float y = (event.getY() + mPreY) / 2;
                drawPoints.add(new PointF(x, y));
                mPath.quadTo(mPreX, mPreY, x, y);
                mPreX = event.getX();
                mPreY = event.getY();
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

    private Path getPath(float mPreX, float mPreY) {
        Path mPath = new Path();
        mPath.moveTo(mPreX, mPreY);
        return mPath;
    }

    //撤回
    public void recallDrawPath() {
//        if (recallInfoList.size() > MAX_RECALL_COUNT) {
//            return;
//        }
        if (canRecallDrawPath()) {
            mBufferBitmap.eraseColor(Color.TRANSPARENT);
            DrawInfo drawInfo = drawInfoList.remove(drawInfoList.size() - 1);
            recallInfoList.add(drawInfo);
            invalidate();
        }
    }

    //恢复撤回
    public void recallRecallPath() {
        if (canRecallRecallPath()) {
            mBufferBitmap.eraseColor(Color.TRANSPARENT);
            DrawInfo drawInfo = recallInfoList.remove(recallInfoList.size() - 1);
            drawInfoList.add(drawInfo);
            invalidate();
        }
    }

    //清除画板
    public void clear() {
        if (mBufferBitmap != null) {
            drawInfoList.clear();
            recallInfoList.clear();
            mBufferBitmap.eraseColor(Color.TRANSPARENT);
            invalidate();
        }
    }

    private boolean canRecallDrawPath() {
        return drawInfoList.size() > 0;
    }

    private boolean canRecallRecallPath() {
        return recallInfoList.size() > 0;
    }

    public Bitmap saveBitmap() {
        if (drawInfoList.size() <= 0) {
            return null;
        }
        PointF pointF = drawInfoList.get(0).getPoints().get(0);
        PointF leftPoint = pointF;
        PointF topPoint = pointF;
        PointF rightPoint = pointF;
        PointF bottomPoint = pointF;
        for (DrawInfo drawInfo : drawInfoList) {
            for (PointF point : drawInfo.getPoints()) {
                if (point.x < leftPoint.x) {
                    leftPoint = point;
                }
                if (point.y < topPoint.y) {
                    topPoint = point;
                }
                if (point.x > rightPoint.x) {
                    rightPoint = point;
                }
                if (point.y > bottomPoint.y) {
                    bottomPoint = point;
                }
            }
        }
        Bitmap bitmap = Bitmap.createBitmap(mBufferBitmap, (int) leftPoint.x - CUT_RESERVE_SIZE, (int) topPoint.y - CUT_RESERVE_SIZE, (int) (rightPoint.x - leftPoint.x) + CUT_RESERVE_SIZE * 2, (int) (bottomPoint.y - topPoint.y) + CUT_RESERVE_SIZE * 2);
        return bitmap;
//        // 创建一个bitmap 根据我们自定义view的大小
//        Bitmap returnedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565);
//        // 绑定canvas
//        Canvas canvas = new Canvas(returnedBitmap);
//        // 获取视图的背景
//        Drawable bgDrawable = getBackground();
//        if (bgDrawable != null)
//            // 如果有就绘制
//            bgDrawable.draw(canvas);
//        else
//            // 没有就绘制白色
//            canvas.drawColor(Color.WHITE);
////            canvas.drawColor(Color.TRANSPARENT);
//        // 绘制
//        draw(canvas);
//        return returnedBitmap;
    }

    public int getLineWidth() {
        return lineWidth;
    }

    public void setLineWidth(int lineWidth) {
        this.lineWidth = lineWidth;
        mPaint.setStrokeWidth(lineWidth);
        erasePaint.setStrokeWidth(lineWidth);
    }

    public int getLineColor() {
        return lineColor;
    }

    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
        mPaint.setColor(lineColor);
    }

    public Mode getMode() {
        return mMode;
    }

    public void setMode(Mode mMode) {
        this.mMode = mMode;
    }
}
